#include <jni.h>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <android/log.h>
#include <string.h>

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "--zzh-trace-", __VA_ARGS__)


const char *TracerPid = "TracerPid";
const int start = 9;

/**
 * 截取字符串
 */
char *strsub(char *str, int start, int end) {
    // 开辟一个字符串去存储我们的数据，开辟多大计算
    // char sub[end-start];
    int len = end - start;
    char *sub = (char *) malloc(len * sizeof(char) + 1);// 记得加上1 ，在 NDK 一般会采用静态的数组存储 char sub[len]
    // malloc 一定要 free
    // 遍历赋值
    str += start;
    for (int i = 0; i < len; i++) {
        sub[i] = *str;
        str++;// 指针往后逻一位
    }
    // 标记字符串结尾，否则 print 无法判断结尾
    sub[len] = '\0';

    // free(sub);

    return sub;
}
//获取TracePid
int get_real_number_for_str(char *raw) {
    if (raw == NULL) {
        return 0;
    }

    if (strstr(raw, TracerPid) == NULL) {
        return 0;
    }
    //LOGD("---匹配了TracerId: %s\n", raw);
    int end = strlen(raw);
    //LOGD("---字符串长度: %d\n", end);
    char *dest = strsub(raw, start + 2, end - 1);
    //LOGD("---截取后的: %s\n", dest);
    int tid = atoi(dest);
    //LOGD("---转换后的: %d\n", tid);
    return tid;
}

//开启循环轮训检查TracePid字段
void *thread_function(void *argv) {
    int pid = getpid();
    char file_name[20] = {'\0'};
    sprintf(file_name, "/proc/%d/status", pid);
    char linestr[256];
    int i = 0, traceid;
    FILE *fp;
    while (1) {
        i = 0;
        fp = fopen(file_name, "r");
        if (fp == NULL) {
            break;
        }
        while (!feof(fp)) {
            fgets(linestr, 256, fp);
            int res = get_real_number_for_str(linestr);
            if (res != 0) {
                //有被追踪调试，直接退出
                exit(0);
            }
            i++;
        }
        fclose(fp);
        sleep(5);
    }
    return ((void *) 0);
}

void create_thread_check_traceid() {
    pthread_t t_id;
    int err = pthread_create(&t_id, NULL, thread_function, NULL);
    if (err != 0) {
        //LOGD("create thread fail: %s\n", strerror(err));
    }
}



//复写jni_onload完成动态注册
extern "C"
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved) {
    //LOGD("JNI on load...");

    //自己附加
    //LOGD("ptrace myself...");
    //ptrace(PTRACE_TRACEME, 0, 0, 0);

    //检测自己有没有被trace
    create_thread_check_traceid();

    return JNI_VERSION_1_6;
}

//onUnLoad方法，在JNI组件被释放时调用
void JNI_OnUnload(JavaVM *vm, void *reserved) {
    //LOGD("JNI unload...");
}